/**
 * 
 */
package engine.operators;

import its.opt.structures.BOAParams;
import its.util.RandomFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import engine.BoaOperator;
import engine.BoaPopulation;
import engine.ObjectiveFunction;
import engine.Population;
import engine.individuals.ProgramedTrafficNetIndividual;

/**
 * @author test
 * 
 */
@Deprecated
public class RestrictedTournamentReplacementBOAOperator
implements BoaOperator<ProgramedTrafficNetIndividual> {

	private static final Logger LOGGER = Logger
			.getLogger(RestrictedTournamentReplacementBOAOperator.class.getName());
	private int numberOfCompetitors;

	private ObjectiveFunction<ProgramedTrafficNetIndividual> objectiveFunction;

	public RestrictedTournamentReplacementBOAOperator(
			ObjectiveFunction<ProgramedTrafficNetIndividual> objectiveFunction, 
			BOAParams params)
	{
		this.numberOfCompetitors = params.replacementCompetitorsCount;
		this.objectiveFunction = objectiveFunction;
	}

	/*
	 * (non-Javadoc)
	 * @see engine.BoaOperator#apply(engine.BoaPopulation, java.util.List)
	 */
	@Override
	public BoaPopulation<ProgramedTrafficNetIndividual> apply(BoaPopulation<ProgramedTrafficNetIndividual> offspringPopulation,
			List<Population<ProgramedTrafficNetIndividual>> populations) {

		Population<ProgramedTrafficNetIndividual> originalPopulation = populations.get(0);
		int originalPopulationSize = originalPopulation.size();
		int offspringPopulationSize = offspringPopulation.size();
		int chromosomeSize = offspringPopulation.getChromosomeSize();

		int similarpos = 0;

		int winnerChildrenCount = 0;

		List<ProgramedTrafficNetIndividual> replacedIndividuals = new ArrayList<ProgramedTrafficNetIndividual>(
				originalPopulation.getIndividuals());

		for (int j = 0; j < offspringPopulationSize; j++) {
			int mindistance = Integer.MAX_VALUE;
			for (int i = 0; i < numberOfCompetitors; i++) {
				int pos = RandomFactory.getNextInt(originalPopulationSize);
				
				int dist = individualsDistance(offspringPopulation.getIndividuals()
						.get(j), originalPopulation.getIndividuals().get(pos));

				if (dist < mindistance) {
					mindistance = dist;
					similarpos = pos;
					if (dist == 0.0)
						break;
				}
			}
			if (objectiveFunction.compute(offspringPopulation.getIndividuals().get(j)) > objectiveFunction
					.compute(originalPopulation.getIndividuals().get(similarpos))) {
				replacedIndividuals.set(similarpos, offspringPopulation
						.getIndividuals().get(j));
				winnerChildrenCount++;
			}
		}

		BoaPopulation<ProgramedTrafficNetIndividual> replacedPopulation = new BoaPopulation<ProgramedTrafficNetIndividual>(
				replacedIndividuals, chromosomeSize);

		LOGGER.warning("Winner children in this population: " + winnerChildrenCount);
		
		return replacedPopulation;
	}

	private int individualsDistance(
			ProgramedTrafficNetIndividual individual1,
			ProgramedTrafficNetIndividual individual2)
	{
		int dist = 0;
//	  float fdist = 0.0f;

	  int programsSize = individual1.getProgramsSize();
	  
	  for (int i = 0; i < programsSize; i++) {
	  	int diff = Math.abs(individual1.getProgramVariableAt(i) - individual2.getProgramVariableAt(i));
	  	
			if (i < individual1.getPrograms().length-1) {
				// FIXME: deprecated because of this
//	  		dist += Math.min(diff, ProgramedTrafficNetIndividual.MAX_PROGRAM_LENGTH - diff);
	  	} else {
	  		dist += diff;
	  	}
	  }
	  return dist/*+fdist*/;
	}

	@Override
	public Population<ProgramedTrafficNetIndividual> apply(Population<ProgramedTrafficNetIndividual> population) {
    throw new UnsupportedOperationException(
        "Use engine.BoaOperator#apply(engine.BoaPopulation, java.util.List) instead");
	}

}
